home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / tags18.zip / CTAG.C < prev    next >
C/C++ Source or Header  |  1992-05-10  |  75KB  |  2,070 lines

  1. /*
  2.  EPSHeader
  3.  
  4.    File: ctag.c
  5.    Author: J. Kercheval
  6.    Created: Sun, 07/14/1991  17:24:44
  7. */
  8. /*
  9.  EPSRevision History
  10.  
  11.    J. Kercheval  Sat, 07/27/1991  22:08:04  creation
  12.    J. Kercheval  Sun, 08/18/1991  20:58:13  completion of CGetToken()
  13.    J. Kercheval  Wed, 08/21/1991  22:34:49  place function recognition
  14.    J. Kercheval  Wed, 08/21/1991  23:11:17  add defines and macros
  15.    J. Kercheval  Wed, 08/21/1991  23:54:33  add typedef and class parsing
  16.    J. Kercheval  Thu, 08/22/1991  23:53:51  add global variables
  17.    J. Kercheval  Thu, 08/22/1991  23:54:05  add enum, struct, union
  18.    J. Kercheval  Thu, 08/22/1991  23:54:28  add globals via typedefs
  19.    J. Kercheval  Sun, 08/25/1991  23:09:28  complete semantic parser
  20.    J. Kercheval  Tue, 08/27/1991  23:28:34  fix bug in typedef, struct, enum and union declarations
  21.    J. Kercheval  Sat, 08/31/1991  23:58:03  add prototype parsing
  22.    J. Kercheval  Tue, 09/03/1991  22:28:55  move many macros to functions
  23.    J. Kercheval  Tue, 09/03/1991  23:05:34  clean code and consolidate to functions
  24.    J. Kercheval  Wed, 09/04/1991  00:16:21  add GNU tag output format support
  25.    J. Kercheval  Sun, 09/08/1991  13:24:53  minor bug fix in function and global variable parser
  26.    J. Kercheval  Sun, 09/08/1991  21:31:06  fix bug in lexical parser
  27.    J. Kercheval  Mon, 09/09/1991  21:49:19  fix bug in function parser
  28.    J. Kercheval  Mon, 09/09/1991  22:39:12  fix buf in define parser
  29.    J. Kercheval  Tue, 09/10/1991  22:06:09  fix typedef parser
  30.    J. Kercheval  Wed, 09/11/1991  02:04:48  add extern symbol recognition
  31.    J. Kercheval  Wed, 09/11/1991  19:49:11  fix bug in function pointer variable declaration
  32.    J. Kercheval  Wed, 09/11/1991  20:38:13  add support for function pointer variable declarations after first declaration
  33.    J. Kercheval  Wed, 09/11/1991  21:51:37  move #directive parsing between semantic and lexical parser
  34.    J. Kercheval  Thu, 09/12/1991  22:44:43  add support for #ifdef blocks to avoid unmatched parens in ToLevelZero parsing
  35.    J. Kercheval  Wed, 09/18/1991  22:05:02  fix bug in GetToken and DiscardLine
  36.    J. Kercheval  Thu, 09/19/1991  22:26:09  fix bug in lexical parser when parsing non C syntax files
  37.    J. Kercheval  Thu, 10/03/1991  18:15:10  add support for Static declarations
  38.    J. Kercheval  Fri, 10/04/1991  11:13:23  add support for tagging enumeration constants
  39.    J. Kercheval  Mon, 10/07/1991  09:36:07  create CParseEnumerationConstants()
  40.    J. Kercheval  Tue, 11/12/1991  21:46:25  add junk filter on token output
  41.    J. Kercheval  Sat, 03/28/1992  13:50:06  fix a few bugs and add extern "C" parsing
  42.    J. Kercheval  Mon, 05/04/1992  00:50:27  fix preprocessor parsing for line_offset and line continuation in defines
  43. */
  44.  
  45. #include <string.h>
  46.  
  47. #include "ctag.h"
  48. #include "tagio.h"
  49. #include "log.h"
  50.  
  51. #define CBUFSIZE 4096
  52. #define MAX_TOKEN_LENGTH 4096
  53.  
  54.  
  55. /* function for determining if character is whitespace */
  56. #define IsWhite(c) ( _C_white_table[c] )
  57.  
  58. /* the indexed table for white space character lookup */
  59. BOOLEAN _C_white_table[256];
  60.  
  61. /* list of whitespace characters */
  62. char C_white[] = " \f\t\v\n\r";
  63.  
  64.  
  65. /* function for determining if character is a delimiter */
  66. #define IsDelim(c) ( _C_delim_table[c] )
  67.  
  68. /* the indexed table for token delimiter lookup */
  69. BOOLEAN _C_delim_table[256];
  70.  
  71. /* list of token delimiters */
  72. char C_delim[] = " \f\t\v\n\r\"[](){}#;:,.'=-+*/%&|^~!<>?";
  73.  
  74.  
  75. /* function for determining if character is a puncuator */
  76. #define IsPunctuator(c) ( _C_punctuator_table[c] )
  77.  
  78. /* the indexed table for punctuator character lookup */
  79. BOOLEAN _C_punctuator_table[256];
  80.  
  81. /* list of punctuators */
  82. char C_punctuator[] = "[](){},;=";
  83.  
  84. /*
  85.  * symbol type information is tied to the switches in flags in CTags().  This
  86.  * enum is used to denote the type of the current tag for determining where
  87.  * the appropriate name is located
  88.  */
  89. enum SymbolTypeEnum {
  90.     NOP, Function, ProtoType, Structure, TypeDefinition, Macro,
  91.     Enumeration, EnumerationConstant, Union, GlobalVariable, Class,
  92.     Define, Extern, Static
  93. };
  94.  
  95. /* convenient definition */
  96. typedef enum SymbolTypeEnum SymbolType;
  97.  
  98. /* the current file buffer state */
  99. typedef struct BufferStruct {
  100.     char *buffer;               /* current index into the pointer */
  101.     long int token_char_location;       /* current token char location */
  102.     long int token_line_location;       /* current token line in buffer */
  103.     long int token_line_offset; /* offset of current line */
  104.     FILE *infile;
  105.     char Cbuf[CBUFSIZE + 1];    /* input buffer for get_token routine */
  106. } Buffer;
  107.  
  108.  
  109. /* the current input token state */
  110. typedef struct TokenStruct {
  111.     char sbuf1[MAX_TOKEN_LENGTH];       /* the first token buffer */
  112.     long int charloc1;          /* the char location of sbuf1 */
  113.     long int tokenline1;        /* the line number of sbuf1 */
  114.     long int lineoffset1;       /* the line offset of sbuf1 */
  115.  
  116.     char sbuf2[MAX_TOKEN_LENGTH];       /* the second token buffer */
  117.     long int charloc2;          /* the char location of sbuf2 */
  118.     long int tokenline2;        /* the line number of sbuf2 */
  119.     long int lineoffset2;       /* the line offset of sbuf2 */
  120.  
  121.     char *cur_token;            /* pointer to the current token buffer */
  122.     long int *cur_char_location;/* the location of current token */
  123.     long int *cur_token_line;   /* the line of the current token */
  124.     long int *cur_line_offset;  /* the line offset of the current token */
  125.  
  126.     char *prev_token;           /* pointer to the last token buffer */
  127.     long int *prev_char_location;       /* the location of previous token */
  128.     long int *prev_token_line;  /* the line of the previous token */
  129.     long int *prev_line_offset; /* the line offset of the previous token */
  130.  
  131.     int token_count;            /* tokens seen since last */
  132.     int else_nesting_level;     /* levels deep in #else/#elif nest */
  133.  
  134.     BOOLEAN extern_active;      /* minor state for this statement */
  135.     BOOLEAN CPP_extern_active;  /* minor state for this statement */
  136.     BOOLEAN static_active;      /* minor state for this statement */
  137. } Token;
  138.  
  139.  
  140. /*----------------------------------------------------------------------------
  141.  *
  142.  * CParserInit() initializes the tables required by the parser. The tables
  143.  * used are a simple boolean index which are true if the character
  144.  * corresponding to the index is a member of the associated table.
  145.  *
  146.  ---------------------------------------------------------------------------*/
  147.  
  148. void CParserInit()
  149. {
  150.     char *s;
  151.     int i;
  152.  
  153.     /* init the entire block to FALSE */
  154.     for (i = 0; i < 256; i++) {
  155.         _C_delim_table[i] = FALSE;
  156.         _C_white_table[i] = FALSE;
  157.         _C_punctuator_table[i] = FALSE;
  158.     }
  159.  
  160.     /* set the characters in the delim set to TRUE */
  161.     for (s = C_delim; *s; s++) {
  162.         _C_delim_table[*s] = TRUE;
  163.     }
  164.  
  165.     /* set the characters in the white set to TRUE */
  166.     for (s = C_white; *s; s++) {
  167.         _C_white_table[*s] = TRUE;
  168.     }
  169.  
  170.     /* set the characters in the punctuator set to TRUE */
  171.     for (s = C_punctuator; *s; s++) {
  172.         _C_punctuator_table[*s] = TRUE;
  173.     }
  174. }
  175.  
  176.  
  177. /*----------------------------------------------------------------------------
  178.  *
  179.  * CSymbolWanted() returns true if flags are true for the symbol type passed
  180.  * and false otherwise.  The following mapping is done:
  181.  *
  182.  *      Flag        Type
  183.  *      ---------   --------------
  184.  *      flags->cf   FunctionCall
  185.  *      flags->cp   ProtoType
  186.  *      flags->cs   Structure
  187.  *      flags->ct   TypeDefinition
  188.  *      flags->cm   Macro
  189.  *      flags->ce   Enumeration
  190.  *      flags->ck   EnumerationConstant
  191.  *      flags->cu   Union
  192.  *      flags->cv   GlobalVariable
  193.  *      flags->cc   Class
  194.  *      flags->cd   Define
  195.  *
  196.  ---------------------------------------------------------------------------*/
  197.  
  198. BOOLEAN CSymbolWanted(SymbolType type, Flags * flags)
  199. {
  200.     switch (type) {
  201.             case Function:
  202.             if (flags->cf)
  203.                 return TRUE;
  204.             break;
  205.         case ProtoType:
  206.             if (flags->cp)
  207.                 return TRUE;
  208.             break;
  209.         case GlobalVariable:
  210.             if (flags->cv)
  211.                 return TRUE;
  212.             break;
  213.         case Define:
  214.             if (flags->cd)
  215.                 return TRUE;
  216.             break;
  217.         case Macro:
  218.             if (flags->cm)
  219.                 return TRUE;
  220.             break;
  221.         case Structure:
  222.             if (flags->cs)
  223.                 return TRUE;
  224.             break;
  225.         case TypeDefinition:
  226.             if (flags->ct)
  227.                 return TRUE;
  228.             break;
  229.         case Enumeration:
  230.             if (flags->ce)
  231.                 return TRUE;
  232.             break;
  233.         case EnumerationConstant:
  234.             if (flags->ck)
  235.                 return TRUE;
  236.             break;
  237.         case Union:
  238.             if (flags->cu)
  239.                 return TRUE;
  240.             break;
  241.         case Class:
  242.             if (flags->cc)
  243.                 return TRUE;
  244.             break;
  245.         default:
  246.             return FALSE;
  247.             break;
  248.     }
  249.  
  250.     /* not reached */
  251.     return FALSE;
  252. }
  253.  
  254.  
  255. /*----------------------------------------------------------------------------
  256.  *
  257.  * CTokenType() takes the token passed and determines if the token is a
  258.  * special token.  Special tokens require specialized handling in the parser.
  259.  * The function returns the type of token according to the SymbolTypeEnum
  260.  * enumeration.  This routine can only tell so much from one symbol but will
  261.  * return some type for all the *interesting* tokens.  Anything that is
  262.  * loosely defined is given back with the closest type available and the
  263.  * parser must give it contextual meaning
  264.  *
  265.  ---------------------------------------------------------------------------*/
  266.  
  267. SymbolType CTokenType(char *token)
  268. {
  269.     char start[] = "cestu";     /* list of starting characters of symbols */
  270.  
  271.     /* look for dirty rejection */
  272.     if (!strchr(start, token[0]))
  273.         return NOP;
  274.  
  275.     /* structure declarations */
  276.     if (!strcmp(token, "struct"))
  277.         return Structure;
  278.  
  279.     /* type declaration */
  280.     if (!strcmp(token, "typedef"))
  281.         return TypeDefinition;
  282.  
  283.     /* enumeration declaration */
  284.     if (!strcmp(token, "enum"))
  285.         return Enumeration;
  286.  
  287.     /* union declaration */
  288.     if (!strcmp(token, "union"))
  289.         return Union;
  290.  
  291.     /* class declaration */
  292.     if (!strcmp(token, "class"))
  293.         return Class;
  294.  
  295.     /* extern declaration */
  296.     if (!strcmp(token, "extern"))
  297.         return Extern;
  298.  
  299.     /* static declaration */
  300.     if (!strcmp(token, "static"))
  301.         return Static;
  302.  
  303.     /* do not recognize it as anything special */
  304.     return NOP;
  305. }
  306.  
  307.  
  308. /*----------------------------------------------------------------------------
  309.  *
  310.  * CIsDeclarationToken() takes the token passed and determines if the token
  311.  * is a declaration keyword used in C.  The user may define new declaration
  312.  * keywords via use of the typedef keyword.  This alters the syntax of C.  If
  313.  * the syntax is changed in this way it is probable that this routine would
  314.  * not return the correct value.  For the standard uses of this routine that
  315.  * information should not hinder performance for the vast majority of the
  316.  * cases.
  317.  *
  318.  ---------------------------------------------------------------------------*/
  319.  
  320. #define SYMBOL_SIZE 20
  321.  
  322. BOOLEAN CIsDeclarationToken(char *token)
  323. {
  324.     char token_list[][SYMBOL_SIZE] =
  325.     {
  326.         "*ivclsdfuaretp_hn\"",  /* list of starting characters of symbols
  327.                                  * below */
  328.         "*",                    /* pointer */
  329.         "\"C\"",                /* C++ extern for C code */
  330.         "int",                  /* integer declaration */
  331.         "void",                 /* void type */
  332.         "char",                 /* character */
  333.         "long",                 /* long integer */
  334.         "short",                /* short integer */
  335.         "double",               /* double floating point */
  336.         "float",                /* floating point */
  337.         "signed",               /* signed integer */
  338.         "unsigned",             /* unsigned integer */
  339.         "auto",                 /* auto variable (local duration) */
  340.         "register",             /* register variable */
  341.         "static",               /* static variable */
  342.         "struct",               /* structure define */
  343.         "union",                /* union define */
  344.         "enum",                 /* enum defined */
  345.         "typedef",              /* type definition */
  346.         "const",                /* constant variable */
  347.         "extern",               /* external declaration */
  348.         "class",                /* class declaration */
  349.         "friend",               /* class modifier */
  350.         "private",              /* class modifier */
  351.         "protected",            /* class modifier */
  352.         "public",               /* class modifier */
  353.         "volatile",             /* Compiler warning */
  354.         "_based",               /* pointer type */
  355.         "_cdecl",               /* parameter calling sequence, C style */
  356.         "cdecl",                /* parameter calling sequence, C style */
  357.         "_far",                 /* pointer type */
  358.         "far",                  /* pointer type */
  359.         "_huge",                /* pointer type */
  360.         "huge",                 /* pointer type */
  361.         "_near",                /* pointer type */
  362.         "near",                 /* pointer type */
  363.         "_pascal",              /* parameter calling sequence, PASCAL style */
  364.         "pascal",               /* parameter calling sequence, PASCAL style */
  365.         "_fortran",             /* parameter calling sequence, FORTRAN style */
  366.         "_fastcall",            /* parameter calling sequence, via registers */
  367.         "\0"
  368.     };
  369.  
  370.     int index;
  371.  
  372.     /* look for dirty rejection */
  373.     if (!strchr(token_list[0], token[0]))
  374.         return FALSE;
  375.  
  376.     /* march through array until membership is determined */
  377.     for (index = 1; *token_list[index]; (index)++) {
  378.  
  379.         /* return true if token found */
  380.         if (!strcmp(token, token_list[index])) {
  381.             return TRUE;
  382.         }
  383.     }
  384.  
  385.     /* did not find it */
  386.     return FALSE;
  387. }
  388.  
  389.  
  390. /*----------------------------------------------------------------------------
  391.  *
  392.  * COutputToken() will output a token of a given type.  The token is output
  393.  * if the passed token type is requested from the command line.
  394.  *
  395.  ---------------------------------------------------------------------------*/
  396.  
  397. void COutputToken(Token * token, Buffer * token_buffer,
  398.                    SymbolType token_type, FILE * outfile,
  399.                    char *infname, Flags * flags)
  400. {
  401.     char line[MAX_TOKEN_LENGTH];/* the line for use with GNU output format */
  402.  
  403.     long int old_offset;        /* the previous value of the file ptr */
  404.     int line_length;            /* the length of the line */
  405.  
  406.     /* init */
  407.     line[0] = '\0';
  408.  
  409.     /* filter any junk tags */
  410.     if (!flags->filter_junk || !IsDelim(token->prev_token[0])) {
  411.  
  412.         /* check that the symbol is wanted and output it if so */
  413.         if (CSymbolWanted(token_type, flags)) {
  414.  
  415.             /* return if external and externals not wanted */
  416.             if (token->extern_active) {
  417.                 if (!flags->cx) {
  418.                     if (token_type != Function &&
  419.                         token_type != Define &&
  420.                         token_type != Macro) {
  421.                         return;
  422.                     }
  423.                 }
  424.             }
  425.  
  426.             /* return if static and statics are not wanted */
  427.             if (token->static_active) {
  428.                 if (!flags->ci) {
  429.                     if (token_type != Define &&
  430.                         token_type != Macro) {
  431.                         return;
  432.                     }
  433.                 }
  434.             }
  435.  
  436.             /* if Epsilon or GNU output is specified then we need to
  437.                output the full line */
  438.             if (flags->og || flags->oe) {
  439.                 /* store the current file offset, move to the line offset, read
  440.                  * the line into a buffer and restore the file offset */
  441.                 old_offset = ftell(token_buffer->infile);
  442.                 if (fseek(token_buffer->infile,
  443.                           *(token->prev_line_offset), SEEK_SET)) {
  444.                     log_message("# COutputToken() -- internal error - continuing");
  445.                 }
  446.                 else {
  447.                     fgets(line, MAX_TOKEN_LENGTH, token_buffer->infile);
  448.                     line_length = strlen(line);
  449.                     if (line[line_length - 1] == '\n') {
  450.                         line[line_length - 1] = '\0';
  451.                     }
  452.                     if (fseek(token_buffer->infile, old_offset, SEEK_SET)) {
  453.                         log_message("# COutputToken() -- internal error - continuing");
  454.                     }
  455.                 }
  456.             }
  457.  
  458.             OutputTag(outfile, line,
  459.                       token->prev_token, infname,
  460.                       *(token->prev_token_line),
  461.                       *(token->prev_char_location) -
  462.                       strlen(token->prev_token), flags);
  463.         }
  464.     }
  465. }
  466.  
  467.  
  468. /*----------------------------------------------------------------------------
  469.  *
  470.  * CGetToken() will obtain the next token in the line pointed to by lptr and
  471.  * in addition will return FALSE if EOL is reached.  This routine is passed
  472.  * an inbut buffer (Cbuf) and a current pointer into the buffer.  It is the
  473.  * responsibility of this routine to refill the buffer if required.  Quoted
  474.  * strings and single quoted characters are returned as a single token.
  475.  * Comments are completely ignored by this parser.  The token will not exceed
  476.  * max_token_length - 1 in length (not including the end of line delimiter)
  477.  *
  478.  ---------------------------------------------------------------------------*/
  479.  
  480. BOOLEAN CGetToken(FILE * infile,
  481.                    char **buffer,
  482.                    char *Cbuf,
  483.                    char *token,
  484.                    int max_token_length,
  485.                    long int *line_number,
  486.                    long int *char_number,
  487.                    long int *line_offset)
  488. {
  489.     typedef enum parser_state { /* a state of the lexical parser */
  490.         Parse, BeginCommentMaybe, InComment, InCommentEndMaybe, InCPPComment,
  491.         InQuoteNormal, InQuoteLiteral, InSingleQuoteNormal,
  492.         InSingleQuoteLiteral, EndSingleQuote, WhiteSpace, Exit
  493.     } State;
  494.  
  495.     State current_state;        /* the current state of the parser */
  496.  
  497.     char c;                     /* the current character being examined */
  498.     char *t;                    /* pointer into token */
  499.  
  500.     int token_length;           /* the current token length cannot exceed max
  501.                                  * token length */
  502.  
  503.     /* init */
  504.     current_state = WhiteSpace;
  505.     t = token;
  506.     *t = '\0';
  507.     token_length = 0;
  508.  
  509.     /* parse the file for the next token */
  510.     while (TRUE) {
  511.  
  512.         c = **buffer;
  513.  
  514.         /* if the buffer has been completely used, refill the buffer, I make
  515.          * the tacit assumption here that the null character is not a member
  516.          * of the source file */
  517.         if (!c) {
  518.             *buffer = Cbuf;
  519.             if (FillBuffer(infile, Cbuf,
  520.                            (long int) CBUFSIZE)) {
  521.                 c = **buffer;
  522.             }
  523.             else {
  524.  
  525.                 /* return the token if it exists */
  526.                 if (t != token) {
  527.                     *t = '\0';
  528.                     return TRUE;
  529.                 }
  530.                 else
  531.                     return FALSE;
  532.             }
  533.         }
  534.  
  535.         /* react on the state machine */
  536.         switch (current_state) {
  537.  
  538.             case Parse:
  539.                 switch (c) {
  540.  
  541.                     case '/':
  542.  
  543.                         /* return if we already have a token */
  544.                         if (t != token) {
  545.                             (*buffer)--;
  546.                             (*char_number)--;
  547.                             current_state = Exit;
  548.                         }
  549.                         else {
  550.                             /* this may be the begin if a comment or the
  551.                              * division symbol, read the next character after
  552.                              * verifying it the buffer doesn't need refilling */
  553.                             current_state = BeginCommentMaybe;
  554.                             *t = c;
  555.                         }
  556.                         break;
  557.  
  558.                     case '\"':
  559.  
  560.                         /* return if we already have a token */
  561.                         if (t != token) {
  562.                             (*buffer)--;
  563.                             (*char_number)--;
  564.                             current_state = Exit;
  565.                         }
  566.                         else {
  567.                             current_state = InQuoteNormal;
  568.                             *t++ = c;
  569.                             token_length++;
  570.                         }
  571.                         break;
  572.  
  573.                     case '\'':
  574.  
  575.                         /* return if we already have a token */
  576.                         if (t != token) {
  577.                             (*buffer)--;
  578.                             (*char_number)--;
  579.                             current_state = Exit;
  580.                         }
  581.                         else {
  582.                             current_state = InSingleQuoteNormal;
  583.                             *t++ = c;
  584.                             token_length++;
  585.                         }
  586.                         break;
  587.  
  588.                     default:
  589.  
  590.                         /* if it is a delimiter than stop processing */
  591.                         if (IsDelim(c)) {
  592.  
  593.                             /* if a token exists then back up in buffer */
  594.                             if (t != token) {
  595.                                 (*buffer)--;
  596.                                 (*char_number)--;
  597.                             }
  598.                             else {
  599.                                 *t++ = c;
  600.                                 token_length++;
  601.                             }
  602.                             current_state = Exit;
  603.                         }
  604.                         else {
  605.  
  606.                             /* normal character, store it in the token */
  607.                             *t++ = c;
  608.                             token_length++;
  609.                         }
  610.                         break;
  611.                 }
  612.                 break;
  613.  
  614.             case WhiteSpace:
  615.  
  616.                 /* pass over whitespace, backup one char if no longer in
  617.                  * white space region */
  618.                 if (!IsWhite(c)) {
  619.                     current_state = Parse;
  620.                     (*buffer)--;
  621.                     (*char_number)--;
  622.                 }
  623.                 else {
  624.  
  625.                     /* check for newline */
  626.                     if (c == '\n') {
  627.                         (*line_number)++;
  628.                         *line_offset = *char_number + *line_number;
  629.                     }
  630.                 }
  631.                 break;
  632.  
  633.             case BeginCommentMaybe:
  634.                 switch (c) {
  635.  
  636.                     case '/':
  637.                         current_state = InCPPComment;
  638.                         break;
  639.  
  640.                     case '*':
  641.                         current_state = InComment;
  642.                         break;
  643.  
  644.                     default:
  645.                         t++;
  646.                         token_length++;
  647.                         (*buffer)--;
  648.                         (*char_number)--;
  649.                         current_state = Exit;
  650.                         break;
  651.                 }
  652.                 break;
  653.  
  654.             case InComment:
  655.                 switch (c) {
  656.  
  657.                     case '*':
  658.                         /* this is potentially the end of the comment */
  659.                         current_state = InCommentEndMaybe;
  660.                         break;
  661.  
  662.                     case '\n':
  663.                         /* new line just increment state variables */
  664.                         (*line_number)++;
  665.                         *line_offset = *char_number + *line_number;
  666.                         break;
  667.  
  668.                     default:
  669.                         break;
  670.                 }
  671.                 break;
  672.  
  673.             case InCommentEndMaybe:
  674.                 switch (c) {
  675.  
  676.                     case '/':
  677.                         /* this is indeed the end of the comment */
  678.                         current_state = WhiteSpace;
  679.                         break;
  680.  
  681.                     case '*':
  682.                         /* this is also perhaps the end of comment */
  683.                         break;
  684.  
  685.                     case '\n':
  686.                         /* new line just increment state variables */
  687.                         (*line_number)++;
  688.                         *line_offset = *char_number + *line_number;
  689.  
  690.                     default:
  691.                         /* still part of the current comment */
  692.                         current_state = InComment;
  693.                         break;
  694.                 }
  695.                 break;
  696.  
  697.             case InCPPComment:
  698.                 if (c == '\n') {
  699.                     current_state = WhiteSpace;
  700.                     (*line_number)++;
  701.                     *line_offset = *char_number + *line_number;
  702.                 }
  703.                 break;
  704.  
  705.             case InQuoteNormal:
  706.                 switch (c) {
  707.  
  708.                     case '\"':
  709.                         /* end of InQuoteNormal state */
  710.                         current_state = Exit;
  711.                         break;
  712.  
  713.                     case '\\':
  714.                         /* InQuoteLiteral state */
  715.                         current_state = InQuoteLiteral;
  716.                         break;
  717.  
  718.                     default:
  719.                         /* normal dull behavior */
  720.                         break;
  721.                 }
  722.                 *t++ = c;
  723.                 token_length++;
  724.                 break;
  725.  
  726.             case InQuoteLiteral:
  727.                 /* this char is simply copied */
  728.                 current_state = InQuoteNormal;
  729.                 *t++ = c;
  730.                 token_length++;
  731.                 break;
  732.  
  733.             case InSingleQuoteNormal:
  734.                 switch (c) {
  735.  
  736.                     case '\\':
  737.                         /* InQuoteLiteral state */
  738.                         current_state = InSingleQuoteLiteral;
  739.                         break;
  740.  
  741.                     default:
  742.                         /* Just copy the character and move to close quote */
  743.                         current_state = EndSingleQuote;
  744.                         break;
  745.                 }
  746.                 *t++ = c;
  747.                 token_length++;
  748.                 break;
  749.  
  750.             case InSingleQuoteLiteral:
  751.                 /* this char is simply copied */
  752.                 current_state = EndSingleQuote;
  753.                 *t++ = c;
  754.                 token_length++;
  755.                 break;
  756.  
  757.             case EndSingleQuote:
  758.  
  759.                 /* end of InSingleQuote states */
  760.                 current_state = Exit;
  761.                 *t++ = c;
  762.                 token_length++;
  763.                 break;
  764.  
  765.             case Exit:
  766.                 *t = '\0';
  767.                 return TRUE;
  768.                 break;
  769.  
  770.             default:            /* not reached */
  771.                 break;
  772.         }
  773.  
  774.         /* if the token_length has gotten too large then return */
  775.         if (token_length == max_token_length - 1) {
  776.             *t = '\0';
  777.             return TRUE;
  778.         }
  779.  
  780.         /* move to the next buffer location */
  781.         (*buffer)++;
  782.         (*char_number)++;
  783.     }
  784. }
  785.  
  786.  
  787. /*----------------------------------------------------------------------------
  788.  *
  789.  * CFillToken() will obtain the next lexical parser from the buffer and move
  790.  * the token into the Token structure.  TRUE is returned if the lexical
  791.  * parser returns TRUE, otherwise FALSE is returned.
  792.  *
  793.  ---------------------------------------------------------------------------*/
  794.  
  795. BOOLEAN CFillToken(Token * token, Buffer * token_buffer)
  796. {
  797.     BOOLEAN token_found;
  798.  
  799.     /* obtain the next token */
  800.     token_found = CGetToken(token_buffer->infile,
  801.                             &(token_buffer->buffer),
  802.                             token_buffer->Cbuf, token->cur_token,
  803.                             MAX_TOKEN_LENGTH,
  804.                             &(token_buffer->token_line_location),
  805.                             &(token_buffer->token_char_location),
  806.                             &(token_buffer->token_line_offset));
  807.  
  808.     /* if one is around then update the state for that token */
  809.     if (token_found) {
  810.         /* update location variables */
  811.         *(token->cur_char_location) =
  812.             token_buffer->token_char_location;
  813.         *(token->cur_token_line) =
  814.             token_buffer->token_line_location;
  815.         *(token->cur_line_offset) =
  816.             token_buffer->token_line_offset;
  817.     }
  818.  
  819.     return token_found;
  820. }
  821.  
  822.  
  823. /*----------------------------------------------------------------------------
  824.  *
  825.  * CTokenSwap() will swap the token variables and set the prev_ variables
  826.  * correctly
  827.  *
  828.  ---------------------------------------------------------------------------*/
  829.  
  830. void CTokenSwap(Token * token)
  831. {
  832.     char *charswap;             /* temporary swap variable */
  833.     long int *longintswap;      /* temporary swap variable */
  834.  
  835.     /* swap the active token string */
  836.     charswap = token->cur_token;
  837.     token->cur_token = token->prev_token;
  838.     token->prev_token = charswap;
  839.  
  840.     /* swap the active character location */
  841.     longintswap = token->cur_char_location;
  842.     token->cur_char_location = token->prev_char_location;
  843.     token->prev_char_location = longintswap;
  844.  
  845.     /* swap the active line */
  846.     longintswap = token->cur_token_line;
  847.     token->cur_token_line = token->prev_token_line;
  848.     token->prev_token_line = longintswap;
  849.  
  850.     /* swap the active line offset */
  851.     longintswap = token->cur_line_offset;
  852.     token->cur_line_offset = token->prev_line_offset;
  853.     token->prev_line_offset = longintswap;
  854. }
  855.  
  856.  
  857. /*----------------------------------------------------------------------------
  858.  *
  859.  * CDiscardLine() will move past all the characters up to the next EOL that
  860.  * is not preceded by a line continuation character.  This routine will
  861.  * return TRUE if there was a '(' character as the first character.  This
  862.  * return value is useful for determining if #defines are macros or simple
  863.  * defines.
  864.  *
  865.  ---------------------------------------------------------------------------*/
  866.  
  867. BOOLEAN
  868. CDiscardLine(FILE * infile, char **buffer, char *Cbuf,
  869.                       long int *line_number, long int *char_number,
  870.                       long int *line_offset)
  871. {
  872.     char c;                     /* the current character being examined */
  873.  
  874.     BOOLEAN line_continue;      /* TRUE if line continuation true */
  875.     BOOLEAN is_macro;           /* TRUE if the first delimiter char is '(' */
  876.     BOOLEAN first_char;         /* TRUE when first character is active */
  877.  
  878.     /* init */
  879.     c = '\0';
  880.     line_continue = FALSE;
  881.     is_macro = FALSE;
  882.     first_char = TRUE;
  883.  
  884.     /* loop until non continued EOL encountered */
  885.     do {
  886.  
  887.         /* handle the newline */
  888.         if (c == '\n') {
  889.             line_continue = FALSE;
  890.             (*line_number)++;
  891.             *line_offset = *char_number + *line_number - 1;
  892.         }
  893.  
  894.         c = **buffer;
  895.         (*buffer)++;
  896.         (*char_number)++;
  897.  
  898.         /* if the buffer has been completely used, refill the buffer, I make
  899.          * the tacit assumption here that the null character is not a member
  900.          * of the source file */
  901.         if (!c) {
  902.             *buffer = Cbuf;
  903.             if (FillBuffer(infile, Cbuf,
  904.                            (long int) CBUFSIZE)) {
  905.                 c = **buffer;
  906.                 (*char_number)--;
  907.             }
  908.             else {
  909.  
  910.                 /* end of file reached */
  911.                 return is_macro;
  912.             }
  913.         }
  914.  
  915.         if (!IsWhite(c))
  916.             line_continue = FALSE;
  917.         
  918.         if (c == '\\')
  919.             line_continue = TRUE;
  920.         
  921.         if (first_char) {
  922.             if (c == '(')
  923.                 is_macro = TRUE;
  924.             first_char = FALSE;
  925.         }
  926.  
  927.     } while (c != '\n' || line_continue);
  928.  
  929.     (*line_number)++;
  930.     *line_offset = *char_number + *line_number - 1;
  931.     
  932.     return is_macro;
  933. }
  934.  
  935.  
  936. /*----------------------------------------------------------------------------
  937.  *
  938.  * CParseDefine() will parse macros and defines in standard C syntax and
  939.  * distinguish between a macro and a define, if there is a punctuator '(' as
  940.  * the first character after the token, then it is a macro.
  941.  *
  942.  ---------------------------------------------------------------------------*/
  943.  
  944. void CParseDefine(Token * token, Buffer * token_buffer,
  945.                    FILE * outfile, char *infname, Flags * flags)
  946. {
  947.     SymbolType tmptype;         /* a temporay type variable */
  948.  
  949.     BOOLEAN token_found;
  950.     BOOLEAN is_macro;
  951.  
  952.     token_found = CFillToken(token, token_buffer);
  953.     if (token_found) {
  954.  
  955.         /* save the previous values */
  956.         CTokenSwap(token);
  957.  
  958.         /* get rid of the rest of the line and return the define type */
  959.         is_macro =
  960.             CDiscardLine(token_buffer->infile,
  961.                          &(token_buffer->buffer),
  962.                          token_buffer->Cbuf,
  963.                          &(token_buffer->token_line_location),
  964.                          &(token_buffer->token_char_location),
  965.                          &(token_buffer->token_line_offset));
  966.  
  967.         /* react on the token */
  968.         if (is_macro) {
  969.             tmptype = Macro;
  970.         }
  971.         else {
  972.             tmptype = Define;
  973.         }
  974.  
  975.         /* output the token */
  976.         COutputToken(token, token_buffer, tmptype,
  977.                      outfile, infname, flags);
  978.     }
  979. }
  980.  
  981.  
  982. /*----------------------------------------------------------------------------
  983.  *
  984.  * CParsePreprocessorDirective() will parse preprocessor directives in
  985.  * standard C syntax
  986.  *
  987.  ---------------------------------------------------------------------------*/
  988.  
  989. void CParsePreprocessorDirective(Token * token, Buffer * token_buffer,
  990.                                FILE * outfile, char *infname, Flags * flags)
  991. {
  992.     BOOLEAN token_found;
  993.  
  994.     token_found = CFillToken(token, token_buffer);
  995.     if (token_found) {
  996.  
  997.         /* deal with a define directive */
  998.         if (!strcmp(token->cur_token, "define")) {
  999.             CParseDefine(token, token_buffer, outfile, infname, flags);
  1000.         }
  1001.         else {
  1002.  
  1003.             /* increment the else block level pointer */
  1004.             if (!strcmp(token->cur_token, "else")) {
  1005.                 token->else_nesting_level++;
  1006.             }
  1007.             else {
  1008.                 /* decrement the else block level pointer */
  1009.                 if (!strcmp(token->cur_token, "endif")) {
  1010.                     if (token->else_nesting_level)
  1011.                         token->else_nesting_level--;
  1012.                 }
  1013.                 else {
  1014.  
  1015.                     /* if an else has not already been seen then increment
  1016.                      * the level */
  1017.                     if (!strcmp(token->cur_token, "elif")) {
  1018.                         token->else_nesting_level++;
  1019.                     }
  1020.                 }
  1021.             }
  1022.  
  1023.             /* remove the rest of the directive line including line
  1024.              * continuation characters */
  1025.             CDiscardLine(token_buffer->infile,
  1026.                          &(token_buffer->buffer),
  1027.                          token_buffer->Cbuf,
  1028.                          &(token_buffer->token_line_location),
  1029.                          &(token_buffer->token_char_location),
  1030.                          &(token_buffer->token_line_offset));
  1031.         }
  1032.     }
  1033. }
  1034.  
  1035.  
  1036. /*----------------------------------------------------------------------------
  1037.  *
  1038.  * CNextToken() will obtain the next token in the buffer and update the
  1039.  * appropriate variables.
  1040.  *
  1041.  ---------------------------------------------------------------------------*/
  1042.  
  1043. BOOLEAN CNextToken(Token * token, Buffer * token_buffer, FILE * outfile,
  1044.                     char *infname, Flags * flags)
  1045. {
  1046.     BOOLEAN token_found;
  1047.     BOOLEAN cycle;
  1048.  
  1049.     do {
  1050.         /* obtain the next token */
  1051.         token_found = CFillToken(token, token_buffer);
  1052.  
  1053.         /* check for preprocessing directives and parse them if found */
  1054.         if (token->cur_token[0] == '#' && token_found) {
  1055.  
  1056.             /* parse the directive and loop back to get another token */
  1057.             CParsePreprocessorDirective(token, token_buffer,
  1058.                                         outfile, infname, flags);
  1059.             cycle = TRUE;
  1060.         }
  1061.         else {
  1062.  
  1063.             /* we found a token to pass to the semantic parser */
  1064.             cycle = FALSE;
  1065.         }
  1066.     } while (cycle);
  1067.  
  1068.     /* return it */
  1069.     return token_found;
  1070. }
  1071.  
  1072.  
  1073. /*----------------------------------------------------------------------------
  1074.  *
  1075.  * CToLevelZero() will increment the nesting level and then parse tokens
  1076.  * until level zero has been reached again.  If tokens are no longer
  1077.  * available this loop will stop.
  1078.  *
  1079.  ---------------------------------------------------------------------------*/
  1080.  
  1081. void CToLevelZero(Token * token, Buffer * token_buffer,
  1082.                    FILE * outfile, char *infname, Flags * flags)
  1083. {
  1084.     char open_brace[] = "{[(";  /* open brace set */
  1085.     char close_brace[] = ")]}"; /* close brace set */
  1086.  
  1087.     int nesting_level = 1;
  1088.  
  1089.     token->else_nesting_level = 0;
  1090.  
  1091.     while (nesting_level) {
  1092.         if (CGetToken(token_buffer->infile, &(token_buffer->buffer),
  1093.                       token_buffer->Cbuf, token->cur_token,
  1094.                       MAX_TOKEN_LENGTH,
  1095.                       &(token_buffer->token_line_location),
  1096.                       &(token_buffer->token_char_location),
  1097.                       &(token_buffer->token_line_offset))) {
  1098.             if (token->cur_token[0] == '#') {
  1099.                 CParsePreprocessorDirective(token, token_buffer,
  1100.                                             outfile, infname, flags);
  1101.             }
  1102.             else {
  1103.  
  1104.                 /* only count open brace, parens and brackets within blocks
  1105.                  * of one element of an ifdef code block */
  1106.                 if (!token->else_nesting_level) {
  1107.                     if (strchr(open_brace, token->cur_token[0])) {
  1108.                         nesting_level++;
  1109.                     }
  1110.                     else {
  1111.                         if (strchr(close_brace, token->cur_token[0])) {
  1112.                             nesting_level--;
  1113.                         }
  1114.                     }
  1115.                 }
  1116.             }
  1117.         }
  1118.         else
  1119.             nesting_level = 0;
  1120.     }
  1121. }
  1122.  
  1123.  
  1124. /*----------------------------------------------------------------------------
  1125.  *
  1126.  * CToPunctuator() will parse tokens until the next punctuator has been
  1127.  * reached.  If tokens are no longer available this loop will stop.  If this
  1128.  * loop is successful the found flag declared in the host routine will be
  1129.  * set.
  1130.  *
  1131.  ---------------------------------------------------------------------------*/
  1132.  
  1133. BOOLEAN CToPunctuator(Token * token, Buffer * token_buffer, FILE * outfile,
  1134.                        char *infname, Flags * flags)
  1135. {
  1136.     BOOLEAN punctuator_found;
  1137.  
  1138.     /* init and parse through until the first punctuator is found */
  1139.     token->token_count = 0;
  1140.     punctuator_found = FALSE;
  1141.     while (!punctuator_found) {
  1142.         token->token_count++;
  1143.         CTokenSwap(token);
  1144.         if (!CNextToken(token, token_buffer, outfile, infname, flags)) {
  1145.             break;
  1146.         }
  1147.         else {
  1148.             if (IsPunctuator(token->cur_token[0]))
  1149.                 punctuator_found = TRUE;
  1150.         }
  1151.     }
  1152.  
  1153.     /* return value */
  1154.     return punctuator_found;
  1155. }
  1156.  
  1157.  
  1158. /*----------------------------------------------------------------------------
  1159.  *
  1160.  * CParseParens() will move through a declaration in parentheses and place
  1161.  * the correct valid token as prev_token.  This return TRUE if a '[' was seen
  1162.  * within the parens and false otherwise.
  1163.  *
  1164.  ---------------------------------------------------------------------------*/
  1165.  
  1166. BOOLEAN CParseParens(Token * token, Buffer * token_buffer, FILE * outfile,
  1167.                       char *infname, Flags * flags)
  1168. {
  1169.     BOOLEAN token_found;
  1170.     BOOLEAN variable_seen;
  1171.     int brace_ignore = 1;
  1172.  
  1173.     token->else_nesting_level = 0;
  1174.  
  1175.     token_found = TRUE;
  1176.     variable_seen = FALSE;
  1177.     while (brace_ignore &&
  1178.            token_found) {
  1179.  
  1180.         token_found = CNextToken(token, token_buffer, outfile,
  1181.                                  infname, flags);
  1182.  
  1183.         if (token_found &&
  1184.             !token->else_nesting_level) {
  1185.             switch (token->cur_token[0]) {
  1186.  
  1187.                 case '(':
  1188.  
  1189.                     /* increment brace_ignore and continue */
  1190.                     brace_ignore++;
  1191.                     break;
  1192.  
  1193.                 case ')':
  1194.  
  1195.                     /* just decrement brace_ignore if it is positive. If
  1196.                      * brace ignore is not positive at this point then we
  1197.                      * certainly have a syntax error.  Ignore this fact if
  1198.                      * so. */
  1199.                     if (brace_ignore) {
  1200.                         brace_ignore--;
  1201.                     }
  1202.                     break;
  1203.  
  1204.                 case '[':
  1205.  
  1206.                     /* move to end of array bounds */
  1207.                     variable_seen = TRUE;
  1208.                     CToLevelZero(token, token_buffer, outfile,
  1209.                                  infname, flags);
  1210.                     break;
  1211.  
  1212.                 default:
  1213.                     CTokenSwap(token);
  1214.                     break;
  1215.             }
  1216.         }
  1217.     }
  1218.  
  1219.     return variable_seen;
  1220. }
  1221.  
  1222.  
  1223. /*----------------------------------------------------------------------------
  1224.  *
  1225.  * COutputCommaDelimitedToken() will output a token and then parse the
  1226.  * statement until ';' or ',' is reached.  The token is output if the passed
  1227.  * token type is requested from the command line.
  1228.  *
  1229.  ---------------------------------------------------------------------------*/
  1230.  
  1231. void COutputCommaDelimitedToken(Token * token, Buffer * token_buffer,
  1232.                                  SymbolType token_type, FILE * outfile,
  1233.                                  char *infname, Flags * flags)
  1234. {
  1235.     char open_brace[] = "{[(";  /* open brace set */
  1236.     BOOLEAN punctuator_found;
  1237.  
  1238.     /* output the token */
  1239.     COutputToken(token, token_buffer, token_type,
  1240.                  outfile, infname, flags);
  1241.  
  1242.     /* go to the next list punctuator (',' or ';') */
  1243.     punctuator_found = TRUE;
  1244.     while (token->cur_token[0] != ',' &&
  1245.            token->cur_token[0] != ';' &&
  1246.            punctuator_found) {
  1247.         if (strchr(open_brace, token->cur_token[0])) {
  1248.             CToLevelZero(token, token_buffer, outfile, infname, flags);
  1249.         }
  1250.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1251.                                          infname, flags);
  1252.     }
  1253. }
  1254.  
  1255.  
  1256. /*----------------------------------------------------------------------------
  1257.  *
  1258.  * CParseCommaDelimitedList() will parse a token list seperated by commas
  1259.  * until a ';' is found.  The tokens are output if the passed type is
  1260.  * requested from the command line.
  1261.  *
  1262.  ---------------------------------------------------------------------------*/
  1263.  
  1264. void CParseCommaDelimitedList(Token * token, Buffer * token_buffer,
  1265.                                SymbolType token_type, FILE * outfile,
  1266.                                char *infname, Flags * flags)
  1267. {
  1268.     char open_brace[] = "{[(";  /* open brace set */
  1269.     BOOLEAN punctuator_found;
  1270.  
  1271.     /* parse through the list */
  1272.     punctuator_found = TRUE;
  1273.     while (token->cur_token[0] != ';' &&
  1274.            punctuator_found) {
  1275.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1276.                                          infname, flags);
  1277.         if (punctuator_found) {
  1278.             switch (token->cur_token[0]) {
  1279.  
  1280.                 case '(':
  1281.  
  1282.                     /* this is an embedded variable declaration, either a
  1283.                      * complex variable pointer or function pointer, fall
  1284.                      * through after picking out the internal token */
  1285.                     CParseParens(token, token_buffer, outfile,
  1286.                                  infname, flags);
  1287.  
  1288.                 case '[':
  1289.                 case ',':
  1290.                 case ';':
  1291.                 case '=':
  1292.  
  1293.                     /* this is one of the proper ending tokens for this type
  1294.                      * of declaration list, so output it and parse to the
  1295.                      * next correct punctuator */
  1296.                     COutputToken(token, token_buffer, token_type,
  1297.                                  outfile, infname, flags);
  1298.                     while (token->cur_token[0] != ',' &&
  1299.                            token->cur_token[0] != ';' &&
  1300.                            punctuator_found) {
  1301.                         if (strchr(open_brace, token->cur_token[0])) {
  1302.                             CToLevelZero(token, token_buffer, outfile,
  1303.                                          infname, flags);
  1304.                         }
  1305.                         punctuator_found = CToPunctuator(token, token_buffer,
  1306.                                                          outfile, infname,
  1307.                                                          flags);
  1308.                     }
  1309.                     break;
  1310.                 default:
  1311.                     break;
  1312.             }
  1313.         }
  1314.     }
  1315. }
  1316.  
  1317.  
  1318. /*----------------------------------------------------------------------------
  1319.  *
  1320.  * CParseFunctionOrGlobalVariable() will parse a function, prototype or
  1321.  * global variable syntax.
  1322.  *
  1323.  ---------------------------------------------------------------------------*/
  1324.  
  1325. void CParseFunctionOrGlobalVariable(Token * token, Buffer * token_buffer,
  1326.                                      FILE * outfile, char *infname,
  1327.                                      Flags * flags)
  1328. {
  1329.     char buf[MAX_TOKEN_LENGTH]; /* the first token buffer */
  1330.     long int charloc;           /* the char location of sbuf1 */
  1331.     long int tokenline;         /* the line number of sbuf1 */
  1332.     long int lineoffset;        /* the line offset of sbuf1 */
  1333.  
  1334.     BOOLEAN token_found;
  1335.     BOOLEAN punctuator_found;
  1336.     BOOLEAN last_token_known;
  1337.     BOOLEAN variable_seen;
  1338.  
  1339.     /* init */
  1340.     buf[0] = '\0';
  1341.     charloc = 0;
  1342.     tokenline = 1;
  1343.     lineoffset = 0;
  1344.  
  1345.     /* save the previous token */
  1346.     last_token_known = CIsDeclarationToken(token->prev_token);
  1347.     if (!last_token_known) {
  1348.  
  1349.         /* If this is not a known token then it may be a function name. Save
  1350.          * it then look further at the syntax.  This also may be a symbol
  1351.          * previously defined via a typedef which alters the syntax of C/C++ */
  1352.         strcpy(buf, token->prev_token);
  1353.         charloc = *(token->prev_char_location);
  1354.         tokenline = *(token->prev_token_line);
  1355.         lineoffset = *(token->prev_line_offset);
  1356.     }
  1357.  
  1358.     /* This is a function or prototype or global variable go to brace_ignore
  1359.      * level zero again. */
  1360.     variable_seen = CParseParens(token, token_buffer, outfile,
  1361.                                  infname, flags);
  1362.  
  1363.     /* Check to see if this is a function, prototype, or global variable. If
  1364.      * the token is a ';' and last_token_known is false then we assume a
  1365.      * function.  Strange variable declarations may fool this, but not
  1366.      * likely. If the character is a '(' then it is certainly a function or
  1367.      * prototype unless variable_seen is TRUE, then it is a variable. If the
  1368.      * character is a '[', ',' then it is certainly a variable declaration.
  1369.      * If the character is a ';' and last_token_known is true then it is a
  1370.      * variable declaration.  If the token is anything else then it is a
  1371.      * function. */
  1372.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1373.     if (token_found) {
  1374.         switch (token->cur_token[0]) {
  1375.  
  1376.             case ';':
  1377.  
  1378.                 /* determine if a prototype or a variable declaration. if the
  1379.                  * last_token_known is true then it is a global variable.  If
  1380.                  * the token was a symbol defined by a typedef then this
  1381.                  * distinction is incorrect since typedef actually alters
  1382.                  * syntax.  This is correct for the large majority of cases
  1383.                  * since most do not enclose simple variable declarations in
  1384.                  * parens. */
  1385.                 if (last_token_known) {
  1386.  
  1387.                     /* this is a global variable */
  1388.                     COutputToken(token, token_buffer, GlobalVariable,
  1389.                                  outfile, infname, flags);
  1390.                 }
  1391.                 else {
  1392.  
  1393.                     /* this is a prototype, copy saved token back to
  1394.                      * prev_token, output and continue */
  1395.                     strcpy(token->prev_token, buf);
  1396.                     *(token->prev_char_location) = charloc;
  1397.                     *(token->prev_token_line) = tokenline;
  1398.                     *(token->prev_line_offset) = lineoffset;
  1399.                     COutputToken(token, token_buffer, ProtoType,
  1400.                                  outfile, infname, flags);
  1401.                 }
  1402.                 break;
  1403.  
  1404.             case '(':
  1405.  
  1406.                 if (variable_seen) {
  1407.  
  1408.                     /* this is a variable declaration */
  1409.                     COutputCommaDelimitedToken(token, token_buffer,
  1410.                                                GlobalVariable, outfile,
  1411.                                                infname, flags);
  1412.                     CParseCommaDelimitedList(token, token_buffer,
  1413.                                              GlobalVariable, outfile,
  1414.                                              infname, flags);
  1415.                 }
  1416.                 else {
  1417.  
  1418.                     /* move to level zero again */
  1419.                     CToLevelZero(token, token_buffer, outfile,
  1420.                                  infname, flags);
  1421.  
  1422.                     /* obtain the next token */
  1423.                     token_found = CNextToken(token, token_buffer, outfile,
  1424.                                              infname, flags);
  1425.  
  1426.                     if (token_found) {
  1427.  
  1428.                         /* check if prototype, function or function pointer
  1429.                          * variable declaration */
  1430.                         switch (token->cur_token[0]) {
  1431.  
  1432.                             case '=':
  1433.  
  1434.                                 /* this is a function pointer variable
  1435.                                  * declaration */
  1436.                                 COutputCommaDelimitedToken(token,
  1437.                                                            token_buffer,
  1438.                                                            GlobalVariable,
  1439.                                                            outfile,
  1440.                                                            infname, flags);
  1441.                                 CParseCommaDelimitedList(token, token_buffer,
  1442.                                                          GlobalVariable,
  1443.                                                          outfile,
  1444.                                                          infname, flags);
  1445.                                 break;
  1446.  
  1447.                             case ';':
  1448.  
  1449.                                 /* this is a prototype, output it */
  1450.                                 COutputToken(token, token_buffer, ProtoType,
  1451.                                              outfile, infname, flags);
  1452.                                 break;
  1453.  
  1454.                             default:
  1455.  
  1456.                                 /* this is a function */
  1457.                                 COutputToken(token, token_buffer, Function,
  1458.                                              outfile, infname, flags);
  1459.  
  1460.                                 /* parse through function */
  1461.                                 punctuator_found = TRUE;
  1462.                                 while (token->cur_token[0] != '{' &&
  1463.                                        punctuator_found) {
  1464.                                     punctuator_found =
  1465.                                         CToPunctuator(token, token_buffer,
  1466.                                                       outfile, infname,
  1467.                                                       flags);
  1468.                                 }
  1469.                                 if (punctuator_found) {
  1470.                                     CToLevelZero(token, token_buffer, outfile,
  1471.                                                  infname, flags);
  1472.                                 }
  1473.                                 break;
  1474.                         }
  1475.                     }
  1476.                 }
  1477.                 break;
  1478.  
  1479.             case '[':
  1480.             case '=':
  1481.             case ',':
  1482.  
  1483.                 /* global variables */
  1484.                 COutputCommaDelimitedToken(token, token_buffer,
  1485.                                            GlobalVariable, outfile,
  1486.                                            infname, flags);
  1487.                 CParseCommaDelimitedList(token, token_buffer,
  1488.                                          GlobalVariable, outfile,
  1489.                                          infname, flags);
  1490.                 break;
  1491.  
  1492.             default:
  1493.  
  1494.                 /* this is a function, copy saved token back to prev_token,
  1495.                  * output and continue */
  1496.                 strcpy(token->prev_token, buf);
  1497.                 *(token->prev_char_location) = charloc;
  1498.                 *(token->prev_token_line) = tokenline;
  1499.                 *(token->prev_line_offset) = lineoffset;
  1500.                 COutputToken(token, token_buffer, Function,
  1501.                              outfile, infname, flags);
  1502.  
  1503.                 /* parse through function */
  1504.                 punctuator_found = TRUE;
  1505.                 while (token->cur_token[0] != '{' &&
  1506.                        punctuator_found) {
  1507.                     punctuator_found =
  1508.                         CToPunctuator(token, token_buffer, outfile,
  1509.                                       infname, flags);
  1510.                 }
  1511.                 if (punctuator_found) {
  1512.                     CToLevelZero(token, token_buffer, outfile,
  1513.                                  infname, flags);
  1514.                 }
  1515.                 break;
  1516.         }
  1517.     }
  1518. }
  1519.  
  1520.  
  1521. /*----------------------------------------------------------------------------
  1522.  *
  1523.  * CParseNOP() will parse an as of yet unrecognized statement.  If I run into
  1524.  * a punctuator at this time then I have found either a structure declaration
  1525.  * (C++ 2.0), or a global variable declaration.  If the punctuator is '[',
  1526.  * ',', '=', or ';' then it is a global variable declaration.  If the
  1527.  * punctuator is a '{' then we have a structure declaration at this time we
  1528.  * should not run into any closing punctuators or syntax is in a bad way
  1529.  *
  1530.  ---------------------------------------------------------------------------*/
  1531.  
  1532. void CParseNOP(Token * token, Buffer * token_buffer, FILE * outfile,
  1533.                 char *infname, Flags * flags)
  1534. {
  1535.     BOOLEAN token_found;
  1536.  
  1537.     switch (token->cur_token[0]) {
  1538.         case ';':
  1539.         case '=':
  1540.         case ',':
  1541.         case '[':
  1542.  
  1543.             /* global variables are here */
  1544.             COutputCommaDelimitedToken(token, token_buffer,
  1545.                                        GlobalVariable, outfile,
  1546.                                        infname, flags);
  1547.             CParseCommaDelimitedList(token, token_buffer,
  1548.                                      GlobalVariable, outfile,
  1549.                                      infname, flags);
  1550.             token->extern_active = FALSE;
  1551.             token->CPP_extern_active = FALSE;
  1552.             token->static_active = FALSE;
  1553.             break;
  1554.  
  1555.         case '{':
  1556.                 
  1557.             /* validate we are not in a C++ extern for C statements */
  1558.             if (!token->CPP_extern_active) {
  1559.                 
  1560.                 /* this is a structure (C++ syntax) */
  1561.                 /* output it */
  1562.                 COutputToken(token, token_buffer, Structure,
  1563.                              outfile, infname, flags);
  1564.  
  1565.                 /* move through declaration */
  1566.                 CToLevelZero(token, token_buffer, outfile, infname, flags);
  1567.  
  1568.                 /* get the next token */
  1569.                 token_found = CNextToken(token, token_buffer, outfile,
  1570.                                          infname, flags);
  1571.  
  1572.                 /* if a token is available then output the list */
  1573.                 if (token_found) {
  1574.                     CParseCommaDelimitedList(token, token_buffer,
  1575.                                              GlobalVariable, outfile,
  1576.                                              infname, flags);
  1577.                 }                                                      
  1578.                 token->extern_active = FALSE;
  1579.                 token->static_active = FALSE;
  1580.             }
  1581.             
  1582.             break;
  1583.  
  1584.         case '(':
  1585.  
  1586.             CParseFunctionOrGlobalVariable(token, token_buffer, outfile,
  1587.                                            infname, flags);
  1588.             token->extern_active = FALSE;
  1589.             token->CPP_extern_active = FALSE;
  1590.             token->static_active = FALSE;
  1591.             break;
  1592.  
  1593.         case '"':
  1594.                                             
  1595.             if (!strcmp("\"C\"",token->cur_token))
  1596.                 token->CPP_extern_active = TRUE;
  1597.             break;
  1598.             
  1599.         default:
  1600.  
  1601.             /* true NOP */
  1602.             break;
  1603.     }
  1604. }
  1605.  
  1606.  
  1607. /*----------------------------------------------------------------------------
  1608.  *
  1609.  * CParseEnumerationConstants() will parse constants within an enumeration
  1610.  * declaration 
  1611.  *
  1612.  ---------------------------------------------------------------------------*/
  1613.  
  1614. void CParseEnumerationConstants(Token *token, Buffer *token_buffer, 
  1615.                                 FILE *outfile, char *infname, 
  1616.                                 Flags *flags)
  1617. {        
  1618.     BOOLEAN punctuator_found;
  1619.  
  1620.     char open_brace[] = "({[";
  1621.     
  1622.     /* obtain the enumeration constants */
  1623.     punctuator_found = TRUE;
  1624.     
  1625.     while (token->cur_token[0] != '}' &&
  1626.            punctuator_found) {
  1627.         punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1628.                                          infname, flags);
  1629.         if (punctuator_found) {
  1630.             switch (token->cur_token[0]) {
  1631.  
  1632.                 case '}':
  1633.  
  1634.                     /* check that the previous token was not a delimiter */
  1635.                     if (token->prev_token[0] == ',')
  1636.                         break;
  1637.                       
  1638.                 case ',':
  1639.                 case '=':
  1640.  
  1641.                     /* this is one of the proper ending tokens for this type
  1642.                      * of declaration list, so output it and parse to the
  1643.                      * next correct punctuator */
  1644.                     COutputToken(token, token_buffer, EnumerationConstant,
  1645.                                  outfile, infname, flags);
  1646.                     while (token->cur_token[0] != ',' &&
  1647.                            token->cur_token[0] != '}' &&
  1648.                            punctuator_found) {
  1649.                         if (strchr(open_brace, token->cur_token[0])) {
  1650.                             CToLevelZero(token, token_buffer, outfile,
  1651.                                          infname, flags);
  1652.                         }
  1653.                         punctuator_found = CToPunctuator(token, token_buffer,
  1654.                                                          outfile, infname,
  1655.                                                          flags);
  1656.                     }
  1657.                     break;
  1658.                     
  1659.                 default:
  1660.                     break;
  1661.             }
  1662.         }
  1663.     }
  1664. }
  1665.     
  1666.  
  1667. /*----------------------------------------------------------------------------
  1668.  *
  1669.  * CParseDeclarationStatement() will parse struct, enum and union
  1670.  * declarations.  take the token just before the first punctuator, run
  1671.  * through the top level braces and parse for variables if the first
  1672.  * punctuator is a ';' then this is a global variable declaration, if the
  1673.  * first token[0] is a '{' then this is a global variable declaration.
  1674.  *
  1675.  ---------------------------------------------------------------------------*/
  1676.  
  1677. void CParseDeclarationStatement(Token * token, Buffer * token_buffer,
  1678.                                  SymbolType type, FILE * outfile,
  1679.                                  char *infname, Flags * flags)
  1680. {
  1681.     BOOLEAN token_found;
  1682.     BOOLEAN punctuator_found;
  1683.     BOOLEAN primary_parse;
  1684.  
  1685.     punctuator_found = CToPunctuator(token, token_buffer, outfile,
  1686.                                      infname, flags);
  1687.     if (punctuator_found) {
  1688.  
  1689.         /* init */
  1690.         primary_parse = TRUE;
  1691.  
  1692.         /* switch on current token */
  1693.         switch (token->cur_token[0]) {
  1694.  
  1695.                 /* this is truly an object declaration */
  1696.             case '{':
  1697.  
  1698.                 /* output only if this is not a variable declaration */
  1699.                 if (token->token_count != 1) {
  1700.  
  1701.                     /* output it */
  1702.                     COutputToken(token, token_buffer, type,
  1703.                                  outfile, infname, flags);
  1704.                 }
  1705.  
  1706.                 /* check if enumeration */
  1707.                 if (type == Enumeration) {
  1708.  
  1709.                     CParseEnumerationConstants(token, token_buffer, 
  1710.                                                outfile, infname, flags);
  1711.                 }
  1712.                 else {
  1713.  
  1714.                     /* move through declaration and fall through */
  1715.                     CToLevelZero(token, token_buffer, outfile, infname, flags);
  1716.                 }
  1717.  
  1718.                 /* get the next token, if one not available then break out of
  1719.                  * case */
  1720.                 token_found = CNextToken(token, token_buffer, outfile,
  1721.                                          infname, flags);
  1722.                 if (!token_found)
  1723.                     break;
  1724.  
  1725.                 /* fall through to take care of variable declarations after
  1726.                  * setting pre-parse flag */
  1727.                 primary_parse = FALSE;
  1728.  
  1729.             case ';':
  1730.             case '=':
  1731.             case ',':
  1732.             case '[':
  1733.  
  1734.                 /* if this is the first seen then output it */
  1735.                 if (primary_parse) {
  1736.                     COutputCommaDelimitedToken(token, token_buffer,
  1737.                                                GlobalVariable,
  1738.                                                outfile, infname,
  1739.                                                flags);
  1740.                 }
  1741.  
  1742.                 CParseCommaDelimitedList(token, token_buffer,
  1743.                                          GlobalVariable,
  1744.                                          outfile, infname,
  1745.                                          flags);
  1746.  
  1747.                 break;
  1748.  
  1749.             case '(':
  1750.  
  1751.                 CParseFunctionOrGlobalVariable(token, token_buffer,
  1752.                                                outfile, infname, flags);
  1753.                 break;
  1754.  
  1755.             default:
  1756.  
  1757.                 /* not reached */
  1758.                 break;
  1759.         }
  1760.     }
  1761. }
  1762.  
  1763.  
  1764. /*----------------------------------------------------------------------------
  1765.  *
  1766.  * CParseTypeDefinition() parses the typedef statement.  take the token just
  1767.  * before the first *correct* punctuator, the ';', ',' or the '['.  Tag any
  1768.  * declarations being done here, get the next token
  1769.  *
  1770.  ---------------------------------------------------------------------------*/
  1771.  
  1772. void CParseTypeDefinition(Token * token, Buffer * token_buffer, FILE * outfile,
  1773.                            char *infname, Flags * flags)
  1774. {
  1775.     BOOLEAN token_found;
  1776.     BOOLEAN parens_found;
  1777.     BOOLEAN special_found;
  1778.  
  1779.     int token_count;
  1780.     SymbolType tmptype;
  1781.  
  1782.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  1783.  
  1784.     if (token_found) {
  1785.  
  1786.         /* check the type of the token for future use */
  1787.         tmptype = CTokenType(token->cur_token);
  1788.  
  1789.         /* parse the typedef */
  1790.         parens_found = FALSE;
  1791.         special_found = FALSE;
  1792.         token_count = 0;
  1793.         while (token->cur_token[0] != ';' &&
  1794.                token->cur_token[0] != ',' &&
  1795.                token->cur_token[0] != '[' &&
  1796.                token_found &&
  1797.                !special_found) {
  1798.  
  1799.             /* parse for defines */
  1800.             if (token_found) {
  1801.  
  1802.                 /* handle the punctuators */
  1803.                 switch (token->cur_token[0]) {
  1804.  
  1805.                     case '{':
  1806.  
  1807.                         /* pass through any defines going on here */
  1808.                         if (token->cur_token[0] == '{') {
  1809.  
  1810.                             /* if the token count is > 1 here then we have a
  1811.                              * named declaration and need to output the
  1812.                              * token, output only if the token type is enum,
  1813.                              * struct, or union */
  1814.                             if (token_count > 1 &&
  1815.                                 (tmptype == Structure ||
  1816.                                  tmptype == Enumeration ||
  1817.                                  tmptype == Union)) {
  1818.                                 COutputToken(token, token_buffer,
  1819.                                              tmptype, outfile,
  1820.                                              infname, flags);
  1821.                             }
  1822.  
  1823.                             if (tmptype == Enumeration) {
  1824.  
  1825.                                 CParseEnumerationConstants(token,
  1826.                                                            token_buffer, 
  1827.                                                            outfile, infname, 
  1828.                                                            flags);
  1829.                             }
  1830.                             else {
  1831.  
  1832.                                 /* go back to level 0 */
  1833.                                 CToLevelZero(token, token_buffer, outfile,
  1834.                                              infname, flags);
  1835.                             }
  1836.                         }
  1837.                         break;
  1838.  
  1839.                     case '(':
  1840.  
  1841.                         /* if this is the top level and we have already been
  1842.                          * through a set of parens then we know this to be a
  1843.                          * function typedef so we output the previous token,
  1844.                          * otherwise check the previous token and if it is a
  1845.                          * known keyword then just eat the token and continue
  1846.                          * on our way */
  1847.                         if (parens_found) {
  1848.                             COutputToken(token, token_buffer,
  1849.                                          TypeDefinition, outfile,
  1850.                                          infname, flags);
  1851.                             CToLevelZero(token, token_buffer, outfile,
  1852.                                          infname, flags);
  1853.                             special_found = TRUE;
  1854.                         }
  1855.                         else {
  1856.  
  1857.                             /* Move back to the top level */
  1858.                             CParseParens(token, token_buffer, outfile,
  1859.                                          infname, flags);
  1860.  
  1861.                             /* next paren we find we know we have a token */
  1862.                             parens_found = TRUE;
  1863.  
  1864.                             /* swap to prevent loss of token */
  1865.                             CTokenSwap(token);
  1866.                         }
  1867.                         break;
  1868.  
  1869.                     default:
  1870.  
  1871.                         /* if we have another token after a paren parse then
  1872.                          * we know the token in the parens was nothing
  1873.                          * special */
  1874.                         parens_found = FALSE;
  1875.                         break;
  1876.                 }
  1877.             }
  1878.  
  1879.             /* get another token */
  1880.             CTokenSwap(token);
  1881.             token_found = CNextToken(token, token_buffer, outfile,
  1882.                                      infname, flags);
  1883.             token_count++;
  1884.         }
  1885.  
  1886.         /* output the typedef names if appropriate */
  1887.         if (token->prev_token[0] != '}' &&
  1888.             token_found) {
  1889.  
  1890.             /* don't output the first token if already done */
  1891.             if (!special_found) {
  1892.                 COutputCommaDelimitedToken(token, token_buffer,
  1893.                                            TypeDefinition, outfile,
  1894.                                            infname, flags);
  1895.             }
  1896.  
  1897.             /* parse through the rest of the typedef names */
  1898.             CParseCommaDelimitedList(token, token_buffer,
  1899.                                      TypeDefinition, outfile,
  1900.                                      infname, flags);
  1901.         }
  1902.     }
  1903. }
  1904.  
  1905.  
  1906. /*----------------------------------------------------------------------------
  1907.  *
  1908.  * CParseClass() will parse the C++ class syntax.  take the token just before
  1909.  * the first '{', ',' or ':' and run through the top level braces if there
  1910.  *
  1911.  ---------------------------------------------------------------------------*/
  1912.  
  1913. void CParseClass(Token * token, Buffer * token_buffer, FILE * outfile,
  1914.                   char *infname, Flags * flags)
  1915. {
  1916.     BOOLEAN token_found;
  1917.  
  1918.     token_found = TRUE;
  1919.     while (token->cur_token[0] != '{' &&
  1920.            token->cur_token[0] != ':' &&
  1921.            token->cur_token[0] != ';' &&
  1922.            token_found) {
  1923.  
  1924.         /* save the current token */
  1925.         CTokenSwap(token);
  1926.  
  1927.         /* get the next token */
  1928.         token_found = CNextToken(token, token_buffer, outfile,
  1929.                                  infname, flags);
  1930.     }
  1931.  
  1932.     /* output the class name */
  1933.     if (token_found) {
  1934.         COutputToken(token, token_buffer, Class,
  1935.                      outfile, infname, flags);
  1936.  
  1937.         /* parse through the remainder of the statement */
  1938.         while (token->cur_token[0] != ';' &&
  1939.                token_found) {
  1940.             if (token->cur_token[0] == '{') {
  1941.  
  1942.                 /* move back to the zero level */
  1943.                 CToLevelZero(token, token_buffer, outfile, infname, flags);
  1944.             }
  1945.  
  1946.             token_found = CNextToken(token, token_buffer, outfile,
  1947.                                      infname, flags);
  1948.         }
  1949.     }
  1950. }
  1951.  
  1952.  
  1953. /*----------------------------------------------------------------------------
  1954.  *
  1955.  * CTags() tags an input stream assuming standard ANSI 2.0 C/C++ syntax.
  1956.  * Long tokens are allowed, ANSI requires only 31 significant.
  1957.  *
  1958.  ---------------------------------------------------------------------------*/
  1959.  
  1960. void CTags(FILE * infile, char *infname, FILE * outfile, Flags * flags)
  1961. {
  1962.     SymbolType type;            /* the type of the current token */
  1963.  
  1964.     Buffer input_buffer;        /* the file buffer and state, stack alloc */
  1965.     Buffer *token_buffer = &input_buffer;       /* a convenient pointer */
  1966.  
  1967.     Token token_state;          /* the token state, stack alloc */
  1968.     Token *token = &token_state;/* a convenient pointer to token state */
  1969.  
  1970.     BOOLEAN token_found;        /* set by CNextToken() */
  1971.  
  1972.     /* init the parser engine */
  1973.     CParserInit();
  1974.     token->token_count = 0;
  1975.  
  1976.     /* init the current token buffers */
  1977.     token->cur_token = token->sbuf1;
  1978.     token->cur_char_location = &(token->charloc1);
  1979.     token->cur_token_line = &(token->tokenline1);
  1980.     token->cur_token[0] = '\0';
  1981.     token->cur_line_offset = &(token->lineoffset1);
  1982.     *(token->cur_char_location) = 0;
  1983.     *(token->cur_token_line) = 1;
  1984.     *(token->cur_line_offset) = 0;
  1985.  
  1986.     /* init the previous token buffers */
  1987.     token->prev_token = token->sbuf2;
  1988.     token->prev_char_location = &(token->charloc2);
  1989.     token->prev_token_line = &(token->tokenline2);
  1990.     token->prev_token[0] = '\0';
  1991.     token->prev_line_offset = &(token->lineoffset2);
  1992.     *(token->prev_char_location) = 0;
  1993.     *(token->prev_token_line) = 1;
  1994.     *(token->prev_line_offset) = 0;
  1995.  
  1996.     /* init the input buffers */
  1997.     token_buffer->token_char_location = 0;
  1998.     token_buffer->token_line_location = 1;
  1999.     token_buffer->token_line_offset = 0;
  2000.     token_buffer->Cbuf[0] = '\0';
  2001.     token_buffer->buffer = token_buffer->Cbuf;
  2002.     token_buffer->infile = infile;
  2003.  
  2004.     /* init Extern and Static states */
  2005.     token->extern_active = FALSE;
  2006.     token->CPP_extern_active = FALSE;
  2007.     token->static_active = FALSE;
  2008.  
  2009.     /* get the first token */
  2010.     token_found = CNextToken(token, token_buffer, outfile, infname, flags);
  2011.  
  2012.     /* loop through the file */
  2013.     while (token_found) {
  2014.  
  2015.         /* obtain the token type */
  2016.         type = CTokenType(token->cur_token);
  2017.  
  2018.         /* react on the token type */
  2019.         switch (type) {
  2020.  
  2021.             case NOP:
  2022.                 CParseNOP(token, token_buffer, outfile, infname, flags);
  2023.                 break;
  2024.  
  2025.             case Structure:
  2026.             case Enumeration:
  2027.             case Union:
  2028.                 CParseDeclarationStatement(token, token_buffer, type,
  2029.                                            outfile, infname, flags);
  2030.                 break;
  2031.  
  2032.             case TypeDefinition:
  2033.                 CParseTypeDefinition(token, token_buffer, outfile,
  2034.                                      infname, flags);
  2035.                 break;
  2036.  
  2037.             case Class:
  2038.                 CParseClass(token, token_buffer, outfile, infname, flags);
  2039.                 break;
  2040.  
  2041.             case Extern:
  2042.                 token->extern_active = TRUE;
  2043.                 break;
  2044.  
  2045.             case Static:
  2046.                 token->static_active = TRUE;
  2047.                 break;
  2048.  
  2049.             default:
  2050.                 /* not reached */
  2051.                 break;
  2052.         }
  2053.  
  2054.         if (type != Extern &&
  2055.             type != Static &&
  2056.             type != NOP) {
  2057.  
  2058.             /* turn off the extern and static flag */
  2059.             token->extern_active = FALSE;
  2060.             token->CPP_extern_active = FALSE;
  2061.             token->static_active = FALSE;
  2062.         }
  2063.  
  2064.         /* swap state variables and get the next token */
  2065.         CTokenSwap(token);
  2066.         token_found = CNextToken(token, token_buffer, outfile,
  2067.                                  infname, flags);
  2068.     }
  2069. }
  2070.